#!/bin/bash

# ===============================================
# Raspberry Pi Toolchains(raspberry-pi-cross-compilers): This project
# provides latest automated GCC Cross Compiler & Native (ARM & ARM64)
# build-scripts and precompiled standalone toolchains for Raspberry Pi.

# Copyright (C) 2020 Abhishek Thakur(@abhiTronix) <abhi.una12@gmail.com>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
# ===============================================

# This script auto downloads, compiles, and compresses Cross & Native GCC ARM Toolchain binaries
# targeting Raspberry Pi 32-bit Stretch(Debian 9) and Buster(Debian 10) OSes only.

helpfunction() {
	#helper function that prints custom usage help menu
	echo ""
	echo ""
	figlet -t -k -f /usr/share/figlet/standard.flf "CLI Raspberry Pi Cross Toolchains Builder 32-bit"
	echo ""
	figlet -t -k -f /usr/share/figlet/term.flf "Copyright (c) 2020 abhiTronix"
	echo ""
	echo ""
	echo "Usage: $0 -g [GCC version] -r [Target Pi type] -o [Target Pi OS type]"
	echo -e "\t-g GCC version you want to compile?: (7.1.0|7.2.0|7.3.0|7.4.0|7.5.0|8.1.0|8.2.0|8.3.0|8.4.0|9.1.0|9.2.0|9.3.0|9.4.0|10.1.0|10.2.0|10.3.0)"
	echo -e "\t-r What's yours Target Raspberry Pi type?: (0-1|2-3|3+)"
	echo -e "\t-o What's yours Target Raspberry Pi OS type?: (stretch|buster)"
	echo ""
	echo ""
	exit 1 # Exit script after printing help
}

#input arguments handler
while getopts "g:r:o:" opt; do
	case "$opt" in
	g) GCC_VERSION="$OPTARG" ;;
	r) RPI_TYPE="$OPTARG" ;;
	o) RPIOS_TYPE="$OPTARG" ;;
	?) helpfunction ;; #prints help function for invalid parameter
	esac
done
#validates parameters and print usage helper function in case parameters are missing
if [ -z "$GCC_VERSION" ] || [ -z "$RPI_TYPE" ] || [ -z "$RPIOS_TYPE" ]; then
	echo "Error: Required parameters are missing!"
	helpfunction
fi

#collect parameters from raspbery pi type
if [ "$RPI_TYPE" = "2-3" ]; then
	FOLDER_VERSION=1
	ARCH=armv7-a
	FPU=neon-vfpv4
elif [ "$RPI_TYPE" = "3+" ]; then
	FOLDER_VERSION=2
	ARCH=armv8-a
	FPU=neon-fp-armv8
elif [ "$RPI_TYPE" = "0-1" ]; then
	FOLDER_VERSION=0
	ARCH=armv6
	FPU=vfp
else
	echo "Invalid argument value: $RPI_TYPE"
	exit
fi

#collect dependencies versions from raspberry pi os
if [ "$RPIOS_TYPE" = "stretch" ]; then
	if [ "$GCC_VERSION" == "8.3.0" ]; then
		echo "$GCC_VERSION is not supported on stretch!"
		exit 0
	else
		GCCBASE_VERSION=6.3.0
	fi
elif [ "$RPIOS_TYPE" = "buster" ]; then
	if echo ${GCC_VERSION%.*} "8.3" | awk '{exit ( $1 >= $2 )}'; then
		echo "$GCC_VERSION is not supported on buster!"
		exit 0
	else
		GCCBASE_VERSION=8.3.0
	fi
else
	echo "Invalid argument value: $RPIOS_TYPE"
	exit 1
fi

#collect build directory if not defined
if [ "$BUILDDIR" = "" ]; then
	#select temp directory as default
	echo "Build directory is empty, using temp directory!"
	BUILDDIR=$(dirname "$(mktemp tmp.XXXXXXXXXX -ut)")
fi

#collect programming languages if not defined
if [ "$LANGUAGES" = "" ]; then
	#select `c,c++,fortran` as default
	echo "Building binaries for c,c++,fortran programming languages!"
	LANGUAGES=c,c++,fortran
fi

#pre-defined params
TARGET=arm-linux-gnueabihf
GDB_VERSION=10.2

#validate env variables
if ! [[ "$GCCBASE_VERSION" =~ ^(6.3.0|8.3.0)$ ]]; then exit 1; fi
if ! [[ "$FOLDER_VERSION" =~ ^(0|1|2)$ ]]; then exit 1; fi
if ! [[ "$ARCH" =~ ^(armv6|armv7-a|armv8-a)$ ]]; then exit 1; fi
if ! [[ "$FPU" =~ ^(vfp|neon-vfpv4|neon-fp-armv8)$ ]]; then exit 1; fi
if [ "$BUILDDIR" = "" ]; then exit 1; fi
if [ "$LANGUAGES" = "" ]; then exit 1; fi

URL="https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/CLI%20Base"

if [ "$RPIOS_TYPE" = "buster" ]; then
	URL="$URL/Buster/GCC%20$GCCBASE_VERSION"
	if [ "$RPI_TYPE" = "0-1" ]; then
		URL="$URL/Raspberry%20Pi%201%2C%20Zero/"
	elif [ "$RPI_TYPE" = "2-3" ]; then
		URL="$URL/Raspberry%20Pi%202%2C%203/"
	elif [ "$RPI_TYPE" = "3+" ]; then
		URL="$URL/Raspberry%20Pi%203A%2B%2C%203B%2B%2C%204/"
	else
		echo "Missing RPI_TYPE parameter!"
		exit 1
	fi
elif [ "$RPIOS_TYPE" = "stretch" ]; then
	URL="$URL/Stretch/GCC%20$GCCBASE_VERSION"
	if [ "$RPI_TYPE" = "0-1" ]; then
		URL="$URL/Raspberry%20Pi%201%2C%20Zero/"
	elif [ "$RPI_TYPE" = "2-3" ]; then
		URL="$URL/Raspberry%20Pi%202%2C%203/"
	elif [ "$RPI_TYPE" = "3+" ]; then
		URL="$URL/Raspberry%20Pi%203A%2B%2C%203B%2B%2C%204/"
	else
		echo "Missing RPI_TYPE parameter!"
		exit 1
	fi
else
	echo "Missing RPIOS_TYPE parameter!"
	exit 1
fi

#download binaries if not found
echo "Downloading and Setting up build directories"

DOWNLOADDIR=$BUILDDIR/build_toolchains
INSTALLDIR=$BUILDDIR/cross-pi-gcc-$GCC_VERSION-$FOLDER_VERSION
SYSROOTDIR=$BUILDDIR/cross-pi-gcc-$GCC_VERSION-$FOLDER_VERSION/$TARGET/libc

mkdir -p "$DOWNLOADDIR"
mkdir -p "$INSTALLDIR"

cd "$DOWNLOADDIR" || exit

if [ ! -f "cross-gcc-$GCCBASE_VERSION-pi_$RPI_TYPE.tar.gz" ]; then
	wget -q --no-check-certificate "${URL}cross-gcc-$GCCBASE_VERSION-pi_$RPI_TYPE.tar.gz"
	tar xf cross-gcc-$GCCBASE_VERSION-pi_$RPI_TYPE.tar.gz
	mv -v cross-pi-gcc-$GCCBASE_VERSION-$FOLDER_VERSION/* $INSTALLDIR
	rm -rf cross-pi-gcc-$GCCBASE_VERSION-$FOLDER_VERSION
	rm ./*.tar.*
fi
if [ ! -d "gdb-$GDB_VERSION" ]; then
	if [ ! -f "gdb-$GDB_VERSION.tar.xz" ]; then wget -q --no-check-certificate https://ftp.gnu.org/gnu/gdb/gdb-$GDB_VERSION.tar.xz; fi
	tar xf gdb-$GDB_VERSION.tar.xz
	cd gdb-$GDB_VERSION || exit
	mkdir -p build
	cd "$DOWNLOADDIR" || exit
	rm ./*.tar.*
fi
if [ ! -d "gcc-$GCC_VERSION" ]; then
	if [ ! -f "gcc-$GCC_VERSION.tar.gz" ]; then wget -q --no-check-certificate https://ftp.gnu.org/gnu/gcc/gcc-"$GCC_VERSION"/gcc-"$GCC_VERSION".tar.gz; fi
	tar xf gcc-"$GCC_VERSION".tar.gz
	cd gcc-"$GCC_VERSION" || exit
	mkdir -p build
	sed -i contrib/download_prerequisites -e '/base_url=/s/ftp/http/'
	contrib/download_prerequisites
	rm ./*.tar.*
	cd "$DOWNLOADDIR" || exit
	rm ./*.tar.*
fi

echo "Setting up paths..."
PATH=$BUILDDIR/cross-pi-gcc-$GCC_VERSION-$FOLDER_VERSION/bin:$PATH
unset LD_LIBRARY_PATH #patch

if [ "$GCC_VERSION" != "$GCCBASE_VERSION" ]; then
	cd "$DOWNLOADDIR"/gcc-"$GCC_VERSION"/build || exit
	if [ -n "$(ls -A "$DOWNLOADDIR"/gcc-"$GCC_VERSION"/build)" ]; then rm -rf "$DOWNLOADDIR"/gcc-"$GCC_VERSION"/build/*; fi
	../configure --prefix= --target=$TARGET --enable-languages=$LANGUAGES --with-sysroot=/$TARGET/libc --with-build-sysroot="$SYSROOTDIR" --with-arch=$ARCH --with-fpu=$FPU --with-float=hard --disable-multilib
	make -s -j$(nproc)
	make -s install-strip DESTDIR="$INSTALLDIR"
fi

cd "$DOWNLOADDIR"/gcc-"$GCC_VERSION" || exit
cat gcc/limitx.h gcc/glimits.h gcc/limity.h >$(dirname $($TARGET-gcc -print-libgcc-file-name))/include-fixed/limits.h

echo "Building Cross GDB Binaries..."
cd "$DOWNLOADDIR"/gdb-$GDB_VERSION/build || exit
if [ -n "$(ls -A "$DOWNLOADDIR"/gdb-$GDB_VERSION/build)" ]; then rm -rf "$DOWNLOADDIR"/gdb-$GDB_VERSION/build/*; fi #cleanup
../configure --prefix= --target=$TARGET --with-arch=$ARCH --with-fpu=$FPU --with-float=hard -with-sysroot=/$TARGET/libc --with-build-sysroot="$SYSROOTDIR"
make -s -j$(nproc)
make -s install DESTDIR="$INSTALLDIR"
if [ -n "$(ls -A "$DOWNLOADDIR"/gdb-$GDB_VERSION/build)" ]; then rm -rf "$DOWNLOADDIR"/gdb-$GDB_VERSION/build/*; fi #cleanup
echo "Done Building Cross GDB Binaries..."

mv "$BUILDDIR"/cross-pi-gcc-"$GCC_VERSION"-$FOLDER_VERSION "$HOME"
cd "$HOME" || exit
#compress with maximum possible compression level.
tar cf - cross-pi-gcc-"$GCC_VERSION"-$FOLDER_VERSION | pigz -9 -p 32 >cross-gcc-"$GCC_VERSION"-pi_"$RPI_TYPE".tar.gz
echo "Done Building Cross GCC $GCC_VERSION Binaries..."
rm -rf "$HOME"/cross-pi-gcc-"$GCC_VERSION"-$FOLDER_VERSION

#clean path
PATH=$(echo "$PATH" | sed -e 's;:\?$BUILDDIR/cross-pi-gcc-$GCC_VERSION-$FOLDER_VERSION/bin;;' -e 's;$BUILDDIR/cross-pi-gcc-$GCC_VERSION-$FOLDER_VERSION/bin:\?;;')
